﻿#include "OiPCH.hpp"

using namespace QtCharts;

namespace Oi
{
    namespace PLScannerCore
    {

        class CameraViewerImpl : public Impl<CameraViewer>, public View::Layer
        {

        public:
            void init();

            void exit();

            void live(bool enabled);

        public:
            static void refresh(const Camera::Frame& frame, void* data);

        public:
            void refreshFrame(const Camera::Frame& frame);

        public:
            void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget);

        protected:
            void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
            void mousePressEvent(QGraphicsSceneMouseEvent *event);
            void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
            void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

        public:
            int _touched;
            int _moved;

        public:
            QMutex _mutex;
            std::deque<int> _events;

        public:
            int _w;
            int _h;
            int _shotMode;
            int _workMode;
            int _trigMode;
            int _acquMode;

            int _xOffset;
            int _yOffset;
            int _wOffset;
            int _hOffset;

        };

        void CameraViewerImpl::init()
        {
            OI_Q(CameraViewer);
         
            _touched = 0;
            _moved = 0;

            setParentItem(q->dynamicLayer());

            live(true);
        }

        void CameraViewerImpl::exit()
        {
            live(false);
        }

        void CameraViewerImpl::live(bool enabled)
        {
            OI_Q(CameraViewer);

            q->setForegroundPictures(QMap<int, Core::Picture>());
            q->setBackgroundPictures(QMap<int, Core::Picture>());
            q->setForeground(Core::Picture());
            q->setBackground(Core::Picture());

            if(PLScanner::instance()->simulation)
            {
                return;
            }

            if(enabled)
            {
                _xOffset = PLScanner::instance()->roiX;
                _yOffset = PLScanner::instance()->roiY;

                _wOffset = PLScanner::instance()->roiWidth;
                _hOffset = PLScanner::instance()->roiHeight;

                if (ProductParams::params().radium != 0)
                {
                    double worldY = PosCalib::OiPosCalib()->toCam(ProductParams::params().radium);
                    double camY = Calib::OiCalib()->toImage(Math::Point2d(0, worldY / 1e3)).y() - _hOffset / 2;
                    _yOffset = PLScanner::instance()->offsetRoiY + camY;
                }
            }
            else
            {
                QRectF r(_xOffset, _yOffset, _wOffset, _hOffset);
                r = r.normalized();
                _xOffset = r.x();
                _yOffset = r.y();
                _wOffset = r.width();
                _hOffset = r.height();
            }

            auto driver = Camera::DriverManager::instance()->driver(qPrintable(PLScanner::instance()->cameraDriver));

            auto devices = driver->devices();

            for(auto iter = devices.begin(); iter != devices.end(); ++iter)
            {
                if(!( *iter )->isOpen())
                {
                    ( *iter )->open();
                }
            }

            for(auto iter = devices.begin(); iter != devices.end(); ++iter)
            {
                if(( *iter )->isShot())
                {
                    ( *iter )->stopCapture();
                }
            }


            Camera::Device* device = nullptr;

            if (devices.size() > 0)
            {
                device = devices[0];
            }

            if (device)
            {
                Base::Size size = device->size();

                _w = size.w();
                _h = size.h();

                if(enabled)
                {
                    _shotMode = device->property(Camera::Device::P_ShotMode);
                    _workMode = device->property(Camera::Device::P_WorkMode);
                    _trigMode = device->property(Camera::Device::P_LTrigger);
                    _acquMode = device->property(Camera::Device::P_FTrigger);

                    device->setProperty(Camera::Device::P_Peak0XOffset, 0);
                    device->setProperty(Camera::Device::P_Peak0WOffset, size.w());
                    device->setProperty(Camera::Device::P_Peak0YOffset, 0);
                    device->setProperty(Camera::Device::P_Peak0HOffset, size.h());

                    device->setProperty(Camera::Device::P_WorkMode, Camera::Device::WM_2DONLY);
                    device->setProperty(Camera::Device::P_ShotMode, Camera::Device::SM_Live);
                    device->setProperty(Camera::Device::P_LTrigger, 0);
                    device->setProperty(Camera::Device::P_FTrigger, 0);

                    device->setCallback(refresh, this);

                    device->live();
                }
                else
                {
                    device->setProperty(Camera::Device::P_Peak0WOffset, _wOffset);
                    device->setProperty(Camera::Device::P_Peak0XOffset, _xOffset);
                    device->setProperty(Camera::Device::P_Peak0HOffset, _hOffset);
                    device->setProperty(Camera::Device::P_Peak0YOffset, _yOffset);

                    device->setProperty(Camera::Device::P_WorkMode, Camera::Device::WM_3DONLY);
                    device->setProperty(Camera::Device::P_ShotMode, _shotMode);
                    device->setProperty(Camera::Device::P_LTrigger, _trigMode);
                    device->setProperty(Camera::Device::P_FTrigger, _acquMode);

                    _xOffset = device->property(Camera::Device::P_Peak0XOffset);
                    _yOffset = device->property(Camera::Device::P_Peak0YOffset);
                    _wOffset = device->property(Camera::Device::P_Peak0WOffset);
                    _hOffset = device->property(Camera::Device::P_Peak0HOffset);
                }
            }

            if(!enabled)
            {
                PLScanner::instance()->roiX = _xOffset;
                PLScanner::instance()->roiY = _yOffset;

                PLScanner::instance()->roiWidth = _wOffset;
                PLScanner::instance()->roiHeight = _hOffset;
            }
        }

        void CameraViewerImpl::refresh(const Camera::Frame& frame, void* data)
        {
            CameraViewerImpl* impl = reinterpret_cast<CameraViewerImpl*>( data );

            if(impl == NULL)
            {
                return;
            }

            impl->refreshFrame(frame);
        }

        void CameraViewerImpl::refreshFrame(const Camera::Frame& frame)
        {
            OI_Q(CameraViewer);

            QImage image;
           
            if(frame.image != NULL)
            {
                image = ( *reinterpret_cast<QImage*>( frame.image ) );
            }

            QMutexLocker locker(&_mutex);

            if(_events.size() < 2)
            {
                QMetaObject::invokeMethod(q, "onRefresh", Q_ARG (QImage, image));  _events.push_back(1);
            }
        }


        void CameraViewerImpl::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
        {
            OI_Q(CameraViewer);

            painter->setPen(QPen(_touched > 0 ? Qt::red : Qt::green, 2));
            painter->drawRect(QRectF(_xOffset, _yOffset, _wOffset, _hOffset).normalized());
        }

        void CameraViewerImpl::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
        {
            OI_Q(CameraViewer);

            auto sp = event->pos();

            _touched = 0;
            QRectF rect = QRectF(_xOffset, _yOffset, _wOffset, _hOffset).normalized();

            QRectF tRect(QPointF(rect.left(), rect.top() - 3), QPointF(rect.right(), rect.top() + 3));
            QRectF lRect(QPointF(rect.left() - 3, rect.top()), QPointF(rect.left() + 3, rect.bottom()));
            QRectF bRect(QPointF(rect.left(), rect.bottom() - 3), QPointF(rect.right(), rect.bottom() + 3));
            QRectF rRect(QPointF(rect.right() - 3, rect.top()), QPointF(rect.right() + 3, rect.bottom()));

            if(tRect.contains(sp))
            {
                _touched = 1;
            }
            else if(lRect.contains(sp))
            {
                _touched = 3;
            }
            else if(bRect.contains(sp))
            {
                _touched = 2;
            }
            else if(rRect.contains(sp))
            {
                _touched = 4;
            }

            if(_touched > 0)
            {
                setCursor(_touched <= 2 ? Qt::SplitVCursor : Qt::SplitHCursor);
            }
            else
            {
                setCursor(Qt::ArrowCursor); event->setAccepted(false);
            }
        }

        void CameraViewerImpl::mousePressEvent(QGraphicsSceneMouseEvent *event)
        {
            OI_Q(CameraViewer);

            _moved = 0;
       
            if(event->button() & Qt::LeftButton)
            {
                _moved = _touched;
            }
            else
            {
                _moved = 0;
                event->setAccepted(false);
            }
        }

        void CameraViewerImpl::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
        {
            OI_Q(CameraViewer);

            if(_moved > 0)
            {
                QRectF rect = QRectF(_xOffset, _yOffset, _wOffset, _hOffset).normalized();

                auto sp = event->pos();

                if(_moved == 1)
                {
                    _yOffset = sp.y();
                }
                else if(_moved == 2)
                {
                    _hOffset = sp.y() - _yOffset;
                }
                else if(_moved == 3)
                {
                    _xOffset = sp.x();
                }
                else if(_moved == 4)
                {
                   _wOffset = sp.x() - _xOffset;
                }
            }
            else
            {
                event->setAccepted(false);
            }
        }

        void CameraViewerImpl::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
        {
            OI_Q(CameraViewer);

            if(event->button() & Qt::LeftButton)
            {
                _moved = 0;
            }
        }

        CameraViewer::CameraViewer(QWidget * parent /*= nullptr*/)
            : OperViewer(parent)
        {
            OI_I(CameraViewer)->init();
        }

        CameraViewer::~CameraViewer()
        {
            OI_E(CameraViewer)->exit();
        }

        void CameraViewer::onRefresh(QImage image)
        {
            OI_F(CameraViewer);

            QMutexLocker locker(&d->_mutex);

            if(!d->_events.empty())
            {
                d->_events.pop_back();
            }

            display(image);
        }
  
    }
}
